﻿using Bmz.IM.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Bmz.IM.Communication
{
    public class IMEngine : IEngine
    {
        #region 字段
        UserVO currentUser = null;
        IPEndPoint currentIPEndPoint = null;
        #endregion

        #region 属性
        public Dictionary<string, Action<MessageVO>> EventDict { get; set; }
        public IPEndPoint CurrentIPEndPoint
        {
            get
            {
                return currentIPEndPoint;
            }
        }
        public UserVO CurrentUser
        {
            get
            {
                return currentUser;
            }
        }
        #endregion

        #region 方法

        public void Initialize(IPEndPoint ipEndPoint)
        {
            EventDict = new Dictionary<string, Action<MessageVO>>();
            currentIPEndPoint = ipEndPoint;
            Thread receiveThreadUdp = new Thread(ReceiveMessageUdp);
            receiveThreadUdp.Start();
            Thread receiveThreadTcp = new Thread(ReceiveMessageTcp);
            receiveThreadTcp.Start();
        }

        public void Start(UserVO user)
        {
            currentUser = user;
        }

        public void SendMessageUdp(MessageVO messageVO)
        {
            UdpClient sendUdpClient = new UdpClient();
            IPEndPoint remoteIpEndPorint = new IPEndPoint(IPAddress.Parse(messageVO.ToIp), messageVO.ToPort);
            byte[] sendBytes = Encoding.Unicode.GetBytes(JsonConvert.SerializeObject(messageVO));
            sendUdpClient.Send(sendBytes, sendBytes.Length, remoteIpEndPorint);
            sendUdpClient.Close();
        }

        public void SendMessageTcp(MessageVO messageVO)
        {
            TcpClient localTcpClient = new TcpClient();
            IPEndPoint remoteIpEndPorint = new IPEndPoint(IPAddress.Parse(messageVO.ToIp), messageVO.ToPort);
            localTcpClient.Connect(remoteIpEndPorint);
            NetworkStream networkStream = localTcpClient.GetStream();
            BinaryWriter binaryWriter = new BinaryWriter(networkStream);
            string requestMessage = JsonConvert.SerializeObject(messageVO);
            binaryWriter.Write(requestMessage);
            binaryWriter.Close();
            networkStream.Close();
            localTcpClient.Close();
        }

        private void ReceiveMessageUdp()
        {
            UdpClient receiveUdpClient = new UdpClient(currentIPEndPoint);
            IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
            while (true)
            {
                byte[] receiveBytes = receiveUdpClient.Receive(ref remoteIpEndPoint);
                string message = Encoding.Unicode.GetString(receiveBytes);
                MessageVO receiveMessageTran = JsonConvert.DeserializeObject<MessageVO>(message);
                ReceiveAction(receiveMessageTran);
            }
        }

        private void ReceiveMessageTcp()
        {
            TcpListener tcpListener = new TcpListener(currentIPEndPoint);
            tcpListener.Start();
            while (true)
            {
                TcpClient tcpClient = tcpListener.AcceptTcpClient();
                NetworkStream networkStream = tcpClient.GetStream();
                BinaryReader binaryReader = new BinaryReader(networkStream);
                string responseString = binaryReader.ReadString();
                MessageVO messageVO = JsonConvert.DeserializeObject<MessageVO>(responseString);
                binaryReader.Close();
                networkStream.Close();
                tcpClient.Close();
                ReceiveAction(messageVO);
            }
        }

        private void ReceiveAction(MessageVO messageVO)
        {
            if (EventDict.ContainsKey(messageVO.Type))
                EventDict[messageVO.Type](messageVO);
        }
        #endregion
    }
}
